﻿using Microsoft.Extensions.DependencyModel;
using Newtonsoft.Json;
using RxxAdmin.Model.Entity;
using SqlSugar;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;

namespace RxxAdmin.Common
{
    public class DBSeed
    {
        private static string SeedDataFolder = "RxxAdmin.Data.json/{0}.tsv";
        /// <summary>
        /// 异步添加种子数据
        /// </summary>
        /// <param name="myContext"></param>
        /// <param name="WebRootPath"></param>
        /// <returns></returns>
        public static async Task SeedAsync(MyContext myContext, string WebRootPath)
        {
            try
            {
                if (string.IsNullOrEmpty(WebRootPath))
                {
                    throw new Exception("获取wwwroot路径时，异常！");
                }

                SeedDataFolder = Path.Combine(WebRootPath, SeedDataFolder);

                Console.WriteLine("************ RxxAdmin DataBase Set *****************");             
                Console.WriteLine($"Master DB ConnectString: {myContext.Db.CurrentConnectionConfig.ConnectionString}");
                Console.WriteLine();
                // 创建数据库
                Console.WriteLine($"Create Database(The Db ConnectString:{MyContext.ConnectionString})...");
                myContext.Db.DbMaintenance.CreateDatabase();
                Console.WriteLine("Database created successfully!");

                // 创建数据库表，遍历指定命名空间下的class，
                // 注意不要把其他命名空间下的也添加进来。
                Console.WriteLine("Create Tables...");

                var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory;
                var referencedAssemblies = System.IO.Directory.GetFiles(path, "RxxAdmin.Model.dll")
                    .Select(Assembly.LoadFrom).ToArray();
                var modelTypes = referencedAssemblies
                    .SelectMany(a => a.DefinedTypes)
                    .Select(type => type.AsType())
                    .Where(x => x.IsClass && x.Namespace is "RxxAdmin.Model.Entity")
                    .ToList();
                modelTypes.ForEach(t =>
                {
                    // 这里只支持添加表，不支持删除
                    // 如果想要删除，数据库直接右键删除，或者联系SqlSugar作者；
                    if (!myContext.Db.DbMaintenance.IsAnyTable(t.Name))
                    {
                        Console.WriteLine(t.Name);
                        myContext.Db.CodeFirst.SplitTables().InitTables(t);
                    }
                });
                Console.WriteLine($"Tables created successfully!");

                JsonSerializerSettings setting = new JsonSerializerSettings();
                JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
                {
                    //日期类型默认格式化处理
                    setting.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat;
                    setting.DateFormatString = "yyyy-MM-dd HH:mm:ss";

                    //空值处理
                    setting.NullValueHandling = NullValueHandling.Ignore;

                    //高级用法九中的Bool类型转换 设置
                    //setting.Converters.Add(new BoolConvert("是,否"));

                    return setting;
                });

                #region SysUser

                if (!await myContext.Db.Queryable<SysUser>().AnyAsync())
                {
                    var data = JsonConvert.DeserializeObject<List<SysUser>>(
                        FileHelper.ReadFile(string.Format(SeedDataFolder, "SysUser"), Encoding.UTF8), setting);

                    myContext.GetEntityDB<SysUser>().InsertRange(data);
                    Console.WriteLine("Table:SysUser created success!");
                }
                else
                {
                    Console.WriteLine("Table:SysUser already exists...");
                }

                #endregion
                #region SysRole

                if (!await myContext.Db.Queryable<SysRole>().AnyAsync())
                {
                    var data = JsonConvert.DeserializeObject<List<SysRole>>(
                        FileHelper.ReadFile(string.Format(SeedDataFolder, "SysRole"), Encoding.UTF8), setting);

                    myContext.GetEntityDB<SysRole>().InsertRange(data);
                    Console.WriteLine("Table:SysRole created success!");
                }
                else
                {
                    Console.WriteLine("Table:SysRole already exists...");
                }

                #endregion
                #region SysMenu

                if (!await myContext.Db.Queryable<SysMenu>().AnyAsync())
                {
                    var data = JsonConvert.DeserializeObject<List<SysMenu>>(
                        FileHelper.ReadFile(string.Format(SeedDataFolder, "SysMenu"), Encoding.UTF8), setting);

                    myContext.GetEntityDB<SysMenu>().InsertRange(data);
                    Console.WriteLine("Table:SysMenu created success!");
                }
                else
                {
                    Console.WriteLine("Table:SysMenu already exists...");
                }

                #endregion
                #region SysUserRole

                if (!await myContext.Db.Queryable<SysUserRole>().AnyAsync())
                {
                    var data = JsonConvert.DeserializeObject<List<SysUserRole>>(
                        FileHelper.ReadFile(string.Format(SeedDataFolder, "SysUserRole"), Encoding.UTF8), setting);

                    myContext.GetEntityDB<SysUserRole>().InsertRange(data);
                    Console.WriteLine("Table:SysUserRole created success!");
                }
                else
                {
                    Console.WriteLine("Table:SysUserRole already exists...");
                }

                #endregion
                #region SysRoleMenu

                if (!await myContext.Db.Queryable<SysRoleMenu>().AnyAsync())
                {
                    var data = JsonConvert.DeserializeObject<List<SysRoleMenu>>(
                        FileHelper.ReadFile(string.Format(SeedDataFolder, "SysRoleMenu"), Encoding.UTF8), setting);

                    myContext.GetEntityDB<SysRoleMenu>().InsertRange(data);
                    Console.WriteLine("Table:SysRoleMenu created success!");
                }
                else
                {
                    Console.WriteLine("Table:SysRoleMenu already exists...");
                }

                #endregion

                //种子初始化
                await SeedDataAsync(myContext.Db);

                Console.WriteLine($"Done seeding database!");
            }
            catch (Exception ex)
            {
                throw new Exception(
                    $"1、若是Mysql,查看常见问题:https://github.com/anjoy8/Blog.Core/issues/148#issue-776281770 \n" +
                    $"2、若是Oracle,查看常见问题:https://github.com/anjoy8/Blog.Core/issues/148#issuecomment-752340231 \n" +
                    "3、其他错误：" + ex.Message);
            }
        }

        /// <summary>
        /// 种子初始化数据
        /// </summary>
        /// <param name="myContext"></param>
        /// <returns></returns>
        private static async Task SeedDataAsync(ISqlSugarClient db)
        {
            // 获取所有种子配置-初始化数据
            var seedDataTypes = AssemblysExtensions.GetAllAssemblies().SelectMany(s => s.DefinedTypes)
                .Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass)
                .Where(u =>
                {
                    var esd = u.GetInterfaces()
                        .FirstOrDefault(i => i.HasImplementedRawGeneric(typeof(IEntitySeedData<>)));
                    if (esd is null)
                    {
                        return false;
                    }
                    return false;
                });

            if (!seedDataTypes.Any()) return;
            foreach (var seedType in seedDataTypes)
            {
                dynamic instance = Activator.CreateInstance(seedType);
                //初始化数据
                {
                    var seedData = instance.InitSeedData();
                    if (seedData != null && Enumerable.Any(seedData))
                    {
                        var entityType = seedType.GetInterfaces().First().GetGenericArguments().First();
                        var entity = db.EntityMaintenance.GetEntityInfo(entityType);

                        if (!await db.Queryable(entity.DbTableName, "").AnyAsync())
                        {
                            await db.Insertable(Enumerable.ToList(seedData)).ExecuteCommandAsync();
                            Console.WriteLine($"Table:{entity.DbTableName} init success!");
                        }
                    }
                }

                //种子数据
                {
                    var seedData = instance.SeedData();
                    if (seedData != null && Enumerable.Any(seedData))
                    {
                        var entityType = seedType.GetInterfaces().First().GetGenericArguments().First();
                        var entity = db.EntityMaintenance.GetEntityInfo(entityType);

                        await db.Storageable(Enumerable.ToList(seedData)).ExecuteCommandAsync();
                        Console.WriteLine($"Table:{entity.DbTableName} seedData success!");
                    }
                }

                //自定义处理
                {
                    await instance.CustomizeSeedData(db);
                }
            }
        }

    }
}
